<?php
namespace Itaoke;


class TopClient{
    
    public $appkey;
    public $secretKey;
    // 生成
//    public $gatewayUrl = "http://router.itaoke.org/api";
    // 备用
    public $gatewayUrl = "http://router.itaokecms.com/api";
    
    public $format = "json";
    
    /** 是否打开入参check**/
    public $checkRequest = true;
    protected $signMethod = "md5";
    protected $apiVersion = "1.0";
    protected $sdkVersion = "top-sdk-php-20190618";
    public $_CachePath;
    public $_method = "";
    public $_saveCache = false;
    
    public function __construct(){
        $this->_CachePath = BASE_PATH . "ItaokeAPI/";
    }
    
    protected function generateSign($params){
        ksort($params);
        $stringToBeSigned = $this->secretKey;
        foreach ($params as $k => $v)
        {
            $stringToBeSigned .= "$k$v";
        }
        unset($k, $v);
        $stringToBeSigned .= $this->secretKey;
        return strtoupper(md5($stringToBeSigned));
    }
    
    public function saveCacheData ($id,$result){
        if($this->_saveCache == false) return false;
        $idkey = substr($id,0,2);
        if (!is_dir($this->_CachePath)) {
            mkdir($this->_CachePath);
        }
        if (!is_dir($this->_CachePath .$this->_method)) {
            mkdir($this->_CachePath .$this->_method);
        }
        if (!is_dir($this->_CachePath .$this->_method.'/'.$idkey)) {
            mkdir($this->_CachePath .$this->_method.'/'.$idkey);
        }
        $filepath = $this->_CachePath .$this->_method.'/'.$idkey;
        if (is_dir($filepath)) {
            $filename = $filepath .'/'.$id .'.cache';
            @file_put_contents($filename,$result);
        }
    }
    
    public function getCacheData ($id){
        $idkey = substr($id,0,2);
        $filename = $this->_CachePath .$this->_method .'/'.$idkey .'/'.$id .'.cache';
        if(file_exists($filename)){
            return @file_get_contents($filename);
        }
        return false;
    }
    
    public function curl($url, $postFields = null){
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
  //      curl_setopt($ch, CURLOPT_FAILONERROR, false);
        curl_setopt($ch, CURLOPT_REFERER, $_SERVER["HTTP_HOST"]);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        //https 请求
        if(strlen($url) > 5 && strtolower(substr($url,0,5)) == "https" ) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        }
        if (is_array($postFields) && 0 < count($postFields)){
            $postBodyString = "";
            $postMultipart = false;
            foreach ($postFields as $k => $v){
                if("@" != substr($v, 0, 1))//判断是不是文件上传
                {
                    $postBodyString .= "$k=" . urlencode($v) . "&";
                }
                else//文件上传用multipart/form-data，否则用www-form-urlencoded
                {
                    $postMultipart = true;
                }
                $postMultipart = true;
            }
            unset($k, $v);
            curl_setopt($ch, CURLOPT_POST, true);
            if ($postMultipart){
                curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
            }else{
                
                curl_setopt($ch, CURLOPT_POSTFIELDS, substr($postBodyString,0,-1));
            }
        }
        $reponse = curl_exec($ch);
        if (curl_errno($ch)){
            throw new \Exception(curl_error($ch),0);
        }else{
            $httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            if (200 !== $httpStatusCode){
                throw new \Exception($reponse,$httpStatusCode);
            }
        }
        curl_close($ch);
        return $reponse;
    }
    
    protected function logCommunicationError($apiName, $requestUrl, $errorCode, $responseTxt){
        $localIp = isset($_SERVER["SERVER_ADDR"]) ? $_SERVER["SERVER_ADDR"] : "CLI";
        $logger = new Logger;
        $logger->conf["log_file"] = $this->_CachePath . "itaoke/top_comm_err_" . $this->appkey . "_" . date("Y-m-d") . ".log";
        $logger->conf["separator"] = "^_^";
        $logData = array(
            date("Y-m-d H:i:s"),
            $apiName,
            $this->appkey,
            $localIp,
            PHP_OS,
            $this->sdkVersion,
            $errorCode,
            str_replace("\n","",$responseTxt)
        );
        $logger->log($logData);
    }
    
    public function execute($request, $session = null){
        $resp = new \stdClass();
        $result = new \stdClass();
        $this->_method = $request->getApiMethodName();
        if(!$this->appkey){
            $result = '{"status":"1002","msg":"Missing Itaoke App Key"}';
            $logger = new Logger;
            $logger->_saveLog = true;
            $logger->conf["log_file"] = $this->_CachePath . "itaoke_logs/top_biz_err_" . $this->appkey . "_" . date("Y-m-d") . ".log";
            $logger->log(array(
                date("Y-m-d H:i:s"),
                $this->_method,
                $result
            ));
            return json_decode($result,true);
        }
        if($this->checkRequest) {
            try {
                $request->check();
            } catch (\Exception $e) {
                $result->status = $e->getCode();
                $result->msg = $e->getMessage();
                return $result;
            }
        }
        //组装系统参数
        $sysParams["app_key"] = $this->appkey;
        //	$sysParams["app_secret"] = $this->secretKey;
        $sysParams["v"] = $this->apiVersion;
        $sysParams["format"] = $this->format;
        $sysParams["sign_method"] = $this->signMethod;
        $sysParams["method"] = $request->getApiMethodName();
        $sysParams["timestamp"] = time();
        $sysParams["domain"] = $_SERVER['SERVER_NAME'] ? $_SERVER['SERVER_NAME'] :'weikeFadan.com';
        $sysParams["client"] = get_client_ip();
        $sysParams["partner_id"] = $this->sdkVersion;
        
        if (null != $session){
            $sysParams["session"] = $session;
        }
        //获取业务参数
        $apiParams = $request->getApiParas();
        //签名
        $sysParams["sign"] = $this->generateSign(array_merge($apiParams, $sysParams));
        
        //系统参数放入GET请求串
        //	$requestUrl = $this->gatewayUrl.$sysParams['method']. "?";
        $requestUrl = $this->gatewayUrl. "?";
        
        foreach ($sysParams as $sysParamKey => $sysParamValue){
            $requestUrl .= "$sysParamKey=" . urlencode($sysParamValue) . "&";
        }
        $requestUrl = substr($requestUrl, 0, -1);
        $cacheid = md5($this->createStrParam($apiParams));
        if (!$resp = $this->getCacheData($cacheid)) {
            //发起HTTP请求
            $logger = new Logger;
            $logger->conf["log_file"] = $this->_CachePath . "itaoke_logs/logs_" . $this->appkey . "_" . date("Y-m-d") . ".log";
            $logger->log(array(
                $this->appkey,
                $this->_method,
                date("Y-m-d H:i:s")
            ));
            try{
                $resp = $this->curl($requestUrl, $apiParams);
                //p($apiParams);
                if(strlen($resp)>50){
                    $this->saveCacheData($cacheid,$resp);
                }
            }catch (\Exception $e){
                $this->logCommunicationError($sysParams["method"],$requestUrl,"HTTP_ERROR_" . $e->getCode(),$e->getMessage());
                $result->status = $e->getCode();
                $result->msg = $e->getMessage();
                return $result;
            }
        }
        //解析TOP返回结果
        $respWellFormed = false;
        if ("json" == $this->format){
            $respObject = json_decode($resp,true);
            if (null !== $respObject){
                $respWellFormed = true;
                /*	foreach ($respObject as $propKey => $propValue){
                 $respObject = $propValue;
                 } */
            }
        }else if("xml" == $this->format){
            $respObject = @simplexml_load_string($resp);
            if (false !== $respObject){
                $respWellFormed = true;
            }
        }
        
        //返回的HTTP文本不是标准JSON或者XML，记下错误日志
        if (false === $respWellFormed){
            $this->logCommunicationError($sysParams["method"],$requestUrl,"HTTP_RESPONSE_NOT_WELL_FORMED",$resp);
            $result->status = 10000;
            $result->msg = "HTTP_RESPONSE_NOT_WELL_FORMED";
            return $result;
        }
        //如果TOP返回了错误码，记录到业务错误日志中
        if ($respObject['status']!='0000'){
            $logger = new Logger;
            $logger->conf["log_file"] = $this->_CachePath . "itaoke_logs/top_biz_err_" . $this->appkey . "_" . date("Y-m-d") . ".log";
            $logger->log(array(
                date("Y-m-d H:i:s"),
                $resp
            ));
        }
        return $respObject;
    }
    
    public function createStrParam ($paramArr){
        $strParam = array();
        foreach ($paramArr as $key =>$val) {
            if ($key != ''&&$val != '') {
                $strParam []= $key .'='.urlencode($val);
            }
        }
        return implode('&',$strParam);
    }
    
    
    
    public function load_api($api_name){
        //require_once '';
        Vendor('Itaoke.request.'.$api_name);
        return new $api_name;
    }
    
}
